package cn.taneroom.lucene.analyzer;

import java.io.IOException;
import java.util.Stack;

import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.util.AttributeSource;

public class SynonymFilter extends TokenFilter {

	private Stack<String> synonymStack;//近义词值栈
	private SynonymEngine engine;//近义词引擎
	private AttributeSource.State current;//属性的克隆
	
	private final CharTermAttribute termAttr;
	private final PositionIncrementAttribute posIncrAttr;
	
	public SynonymFilter(TokenStream in, SynonymEngine engine) {  
        super(in);
        // #1 Define synonym buffer 
        this.synonymStack = new Stack<String>();
        this.engine = engine;
        
        this.termAttr = addAttribute(CharTermAttribute.class);
        this.posIncrAttr = addAttribute(PositionIncrementAttribute.class);
    }
	
	@Override
	public boolean incrementToken() throws IOException {
		if (synonymStack.size() > 0) {
			// #2 Pop buffered synonyms
			String syn = synonymStack.pop();
			restoreState(current);
			termAttr.copyBuffer(syn.toCharArray(), 0, syn.length());
			// #3 Set position increment to 0
			posIncrAttr.setPositionIncrement(0);
			return true;
		}
		// #4 Read next token
		if (input.incrementToken()) {
			return false;
		}
		// #5 Push synonyms onto stack
		if (addAliasesToStack()) {
			// #6 Save current token
			current = captureState();
		}
		// #7 Return current token
		return true;
	}

	private boolean addAliasesToStack() throws IOException {
		// #8 Retrieve synonyms
		String[] synonyms = engine.getSynonyms(termAttr.toString());
		if (synonyms == null) {
			return false;
		}
		// #9 Push synonyms onto stack
		for (String synonym : synonyms) {
			synonymStack.push(synonym);
		}
		return true;
	}

}
